﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using ImageProcessing.LinearFilters;
using Microsoft.Win32;
using System.ComponentModel;
using ImageProcessing.ParameterForms;
using System.Collections.ObjectModel;
//0,3r+0,59G+0,11B
namespace ImageProcessing
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        
        private delegate void UpdateProgressBarDelegate(
        System.Windows.DependencyProperty dp, Object value);
        public MainWindow()
        {
            AHistogramData = new ObservableCollection<Grid>();
            BHistogramData = new ObservableCollection<Grid>();
            InitializeComponent();
            UpdateProgressBarDelegate updatePbDelegate =
                                                new UpdateProgressBarDelegate(progressBar.SetValue);
            LfpOperations.ProgressChangeEventHandler += (o, eventProgressArgs) =>
            {
                Dispatcher.Invoke(updatePbDelegate,
                    System.Windows.Threading.DispatcherPriority.Background,
                    new object[] { ProgressBar.ValueProperty, eventProgressArgs.Value + 1 });
            };
            GradientOperations.ProgressChangeEventHandler += (o, eventProgressArgs) =>
            {
                Dispatcher.Invoke(updatePbDelegate,
                    System.Windows.Threading.DispatcherPriority.Background,
                    new object[] { ProgressBar.ValueProperty, eventProgressArgs.Value + 1 });
            };
        }

        private void BuildHistogram(WriteableBitmap image, ObservableCollection<Grid> histogram)
        {
            histogram.Clear();
            if (image == null) return;
            double[] values = GlobalOperations.GetHistogram(image);
            Grid gridValue;
            for (int i = 0; i < 256; i++)
            {
                gridValue = new Grid();
                gridValue.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1 - values[i], GridUnitType.Star) });
                gridValue.RowDefinitions.Add(new RowDefinition { Height = new GridLength(values[i] * 4, GridUnitType.Star) });
                Rectangle rect = new Rectangle { Fill = new SolidColorBrush { Color = Colors.Green, Opacity = 0.5 }, Margin = new Thickness(-0.5, 0, -0.5, 0) };
                Grid.SetRow(rect, 1);
                Rectangle grade = new Rectangle { Height = 3, VerticalAlignment = System.Windows.VerticalAlignment.Top, Fill = new SolidColorBrush { Color = Colors.Red, Opacity = 0.7 }, };
                Grid.SetRow(grade, 1);
                gridValue.Children.Add(rect);
                gridValue.Children.Add(grade);
                histogram.Add(gridValue);
            }
        }

        public bool ABufferLoaded { get { return BufferA != null; } }

        public ObservableCollection<Grid> AHistogramData { get; private set; }

        private WriteableBitmap _BufferA;
        public WriteableBitmap BufferA
        {
            get { return _BufferA; }
            set
            {
                if (_BufferA != null) _BufferA.Changed -= _BufferA_Changed;
                _BufferA = value;
                if (_BufferA != null)
                {
                    _BufferA.Changed += new EventHandler(_BufferA_Changed);
                    _BufferA_Changed(_BufferA, null);
                }
                OnPropertyChanged("ABufferLoaded");
                if (!(BVisibility.IsChecked ?? false) && !(BVisibility.IsChecked ?? false)) AVisibility.IsChecked = true;
            }
        }

        private void _BufferA_Changed(object sender, EventArgs e)
        {
            BuildHistogram(sender as WriteableBitmap, AHistogramData);
            OnPropertyChanged("BufferA");
        }

        public bool BBufferLoaded { get { return BufferB != null; } }

        public ObservableCollection<Grid> BHistogramData { get; private set; }

        private WriteableBitmap _BufferB;
        public WriteableBitmap BufferB
        {
            get { return _BufferB; }
            set
            {
                if (_BufferB != null) _BufferB.Changed -= _BufferB_Changed;
                _BufferB = value;
                if (_BufferB != null)
                {
                    _BufferB.Changed += new EventHandler(_BufferB_Changed);
                    _BufferB_Changed(_BufferB, null);
                }
                _BufferB = value;
                OnPropertyChanged("BBufferLoaded");
            }
        }

        private void _BufferB_Changed(object sender, EventArgs e)
        {
            BuildHistogram(sender as WriteableBitmap, BHistogramData);
            OnPropertyChanged("BufferB");
        }

        #region FileMenuHandlers

        

        private void MenuItem_SwitchBuffers_Click(object sender, RoutedEventArgs e)
        {
            WriteableBitmap temp = BufferA;
            BufferA = BufferB;
            BufferB = temp;
        }

        private void MenuItem_AtoB_Click(object sender, RoutedEventArgs e)
        { if (BufferA != null) BufferB = new WriteableBitmap(BufferA); }

        private void MenuItem_BtoA_Click(object sender, RoutedEventArgs e)
        { if (BufferB != null) BufferA = new WriteableBitmap(BufferB); }

        private void MenuItem_Exit_Click(object sender, RoutedEventArgs e)
        { Close(); }

        #endregion

        #region ALOMenuHandlers

        private void MenuItem_AddConstantImage_Click(object sender, RoutedEventArgs e)
        {
            FormByteConstant form = new FormByteConstant { Title = "A + constant" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            ALOperations.AddConstant(BufferA, form.Constant);
        }

        private void MenuItem_SubtractConstant_Click(object sender, RoutedEventArgs e)
        {
            FormByteConstant form = new FormByteConstant { Title = "A - constant" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            ALOperations.SubtractConstant(BufferA, form.Constant);
        }

        private void MenuItem_MultipleOnConstant_Click(object sender, RoutedEventArgs e)
        {
            FormUDoubleConstant form = new FormUDoubleConstant { Title = "A * constant" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            ALOperations.MultipleOnConstant(BufferA, form.Constant);
        }

        private void MenuItem_DivideOnConstant_Click(object sender, RoutedEventArgs e)
        {
            FormUDoubleConstant form = new FormUDoubleConstant { Title = "A / constant" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            ALOperations.DivideOnConstant(BufferA, form.Constant);
        }

        private void MenuItem_SumAandB_Click(object sender, RoutedEventArgs e)
        { BufferA = ALOperations.SumAandB(BufferA, BufferB); }

        private void MenuItem_SubtractBfromA_Click(object sender, RoutedEventArgs e)
        { BufferA = ALOperations.SubtractBfromA(BufferA, BufferB); }

        private void MenuItem_LogicalAndConstant_Click(object sender, RoutedEventArgs e)
        {
            FormByteConstant form = new FormByteConstant { Title = "A AND constant" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            ALOperations.LogicalAndConstant(BufferA, form.Constant);
        }

        private void MenuItem_LogicalOrConstant_Click(object sender, RoutedEventArgs e)
        {
            FormByteConstant form = new FormByteConstant { Title = "A OR constant" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            ALOperations.LogicalOrConstant(BufferA, form.Constant);
        }

        private void MenuItem_LogicalXorConstant_Click(object sender, RoutedEventArgs e)
        {
            FormByteConstant form = new FormByteConstant { Title = "A XOR constant" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            ALOperations.LogicalXorConstant(BufferA, form.Constant);
        }

        private void MenuItem_LogicalAandB_Click(object sender, RoutedEventArgs e)
        { BufferA = ALOperations.LogicalAandB(BufferA, BufferB); }

        private void MenuItem_LogicalAorB_Click(object sender, RoutedEventArgs e)
        { BufferA = ALOperations.LogicalAorB(BufferA, BufferB); }

        private void MenuItem_LogicalAxorB_Click(object sender, RoutedEventArgs e)
        { BufferA = ALOperations.LogicalAxorB(BufferA, BufferB); }

        #endregion

        #region FiltersMenuHandlers

        private void MenuItemFilterLinearFirClick(object sender, RoutedEventArgs e)
        {
            var view = new FirView();
            var viewModel = new FirViewModel();
            viewModel.CancelEventHandler += (o, eventArgs) => view.Close();
            
            viewModel.OkEventHandler += (o, eventArgs) =>
                                            {
                                                view.Close();
                                                LfpOperations.Iif(eventArgs.Height,eventArgs.Width,eventArgs.Mask,BufferA);
                                                
                                            };
            view.ViewModel= viewModel;
            view.ShowDialog();
        }

       

        private void MenuItem_FilterLinearAveraging_Click(object sender, RoutedEventArgs e)
        {
            LfpOperations.Averaging(BufferA);
        }

        private void MenuItem_FilterNonLinearMedian_Click(object sender, RoutedEventArgs e)
        {
            var form = new FormByteConstant { Title = "Введите размер окна" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            if (form.Constant % 2 == 1)
                LfpOperations.Median2D(BufferA, form.Constant);
            else
                MessageBox.Show("Константа должна быть нечетной");
        }
        private void MenuItemRankMenuItemClick(object sender, RoutedEventArgs e)
        {
            var view = new WindowSizeRankView();
            var viewModel = new WindowSizeRankViewModel();
            viewModel.CancelEventHandler += (o, eventArgs) => view.Close();
            viewModel.OkEventHandler += (o, eventArgs) =>
            {
                LfpOperations.Rank(BufferA, eventArgs.WindowSize, eventArgs.Rank);
                view.Close();
            };
            view.ViewModel = viewModel;
            view.ShowDialog();
        }

        private void MenuItemMinimalRankClick(object sender, RoutedEventArgs e)
        {
            var form = new FormByteConstant { Title = "Введите размер окна" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            if (form.Constant % 2 == 1)
                LfpOperations.Rank(BufferA, form.Constant,1);
            else
                MessageBox.Show("Константа должна быть нечетной");
        }

        private void MenuItemMaximumRankClick(object sender, RoutedEventArgs e)
        {
            var form = new FormByteConstant { Title = "Введите размер окна" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            if (form.Constant % 2 == 1)
                LfpOperations.Rank(BufferA, form.Constant, form.Constant * form.Constant);
            else
                MessageBox.Show("Константа должна быть нечетной");
        }
  
        #endregion

        #region GlobalOperationsMenuHandlers

        private void MenuItem_GlobalInvert_Click(object sender, RoutedEventArgs e)
        { GlobalOperations.InvertImageOperation(BufferA); }

        private void MenuItem_GlobalBinarizationByLevel_Click(object sender, RoutedEventArgs e)
        {
            FormByteConstant form = new FormByteConstant { Title = "Уровень бинаризации А" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            GlobalOperations.BinarizationByLevelImageOperation(BufferA, form.Constant);
        }

        private void MenuItem_GlobalBinarizationByInterval_Click(object sender, RoutedEventArgs e)
        {
            FormIntervalConstants form = new FormIntervalConstants { Title = "Интервал бинаризации А" };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            GlobalOperations.BinarizationByIntervalImageOperation(BufferA, form.StartValue, form.EndValue);
        }

        #endregion

        private void OpenImage_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog
            {
                Filter = "Файлы рисунков (*.bmp, *.jpg, *.bmp)|*.bmp;*.jpg;*.png",
                Multiselect = false
            };
            bool result = ofd.ShowDialog() ?? false;
            if (!result) return;
            Uri fileUri = new Uri(ofd.FileName, UriKind.Absolute);
            BitmapDecoder decoder = BitmapDecoder.Create(fileUri, BitmapCreateOptions.None, BitmapCacheOption.Default);
            BufferA = new WriteableBitmap(decoder.Frames[0]);
            if (BufferB == null) BufferB = new WriteableBitmap(decoder.Frames[0]);
        }



        private void ScaleImage_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            FormScaleConstants form = new FormScaleConstants { ScaleImage = BufferA };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
            TransformedBitmap tb = new TransformedBitmap(BufferA, new ScaleTransform(form.XScaleValue, form.YScaleValue));
            BufferA = new WriteableBitmap(tb);
        }

        private void RotateImage_Executed(object sender, ExecutedRoutedEventArgs e)
        {
        }

        private void SubImage_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            FormSubImageConstants form = new FormSubImageConstants { SourceImage = BufferA };
            bool result = form.ShowDialog() ?? false;
            if (!result) return;
        }

        private void ImageServiceOperation_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        { e.CanExecute = ABufferLoaded; }

        #region INotifyPropertyChanged parts
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion

        private void MenuItemDifferenceSquareRootClick(object sender, RoutedEventArgs e)
        {
            GradientOperations.DifferenceSquareRoot(BufferA);
        }

        private void MenuItemDifferenceSumModulesClick(object sender, RoutedEventArgs e)
        {
            GradientOperations.DifferenceModule(BufferA);
        }

        private void MenuItem_FilterGradientMaxDifference_Click(object sender, RoutedEventArgs e)
        {
            GradientOperations.MaxDifference(BufferA);
        }

        private void MenuItemRobertsSquareRootClick(object sender, RoutedEventArgs e)
        {
            GradientOperations.RobertsSquareRoot(BufferA);
        }

        private void MenuItemRobertsSumModulesClick(object sender, RoutedEventArgs e)
        {
            GradientOperations.RobertsModule(BufferA);
        }

        private void MenuItemPrewittSquareRootClick(object sender, RoutedEventArgs e)
        {
            GradientOperations.PrevittSquareRoot(BufferA);
        }

        private void MenuItemPrewittSumModulesClick(object sender, RoutedEventArgs e)
        {
            GradientOperations.PrevittModule(BufferA);
        }

        private void MenuItemSobelSquareRootClick(object sender, RoutedEventArgs e)
        {
            GradientOperations.SobelSquareRoot(BufferA);
        }

        private void MenuItemSobelSumModulesClick(object sender, RoutedEventArgs e)
        {
            GradientOperations.SobelModule(BufferA);
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Process.Start("SkyHelp.chm");
        }

        private void MenuItem_Click_1(object sender, RoutedEventArgs e)
        {

        }
    }
}
